using System;
using System.Collections.Generic;
using System.Web.Security;
using Microsoft.SharePoint;
using System.Collections;
using System.Data;

namespace ProjectHT.YKDGVB2012.Core.MemberShip
{
    public class CsRoleProvider: RoleProvider
    {

        #region Custom RoleProvider Properties
        private string _pSiteUrl;
        private string _pMembershipListName;
        private string _pRoleFieldName;

        private SPList _pMembershipList;
        private SPWeb _mySite;
        private SPSite _siteCollection;

        public string SiteURL
        {
            get { return _pSiteUrl; }
        }

        public string ContactMembershipListName
        {
            get { return _pMembershipListName; }
        }

        public SPList MembershipContactList
        {
            get { return _pMembershipList; }
        }

        public string RoleFieldName
        {
            get { return _pRoleFieldName; }
        }
        #endregion

        #region Default Properties
        public override string ApplicationName
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        #endregion

        #region Helper Functions
        //
        // A helper function to retrieve config values from the configuration file.
        //
        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (String.IsNullOrEmpty(configValue))
                return defaultValue;

            return configValue;
        }

        /// <summary>
        /// TODO: This code shouldn't be needed in every function
        /// </summary>
        /// <returns></returns>
        private SPList InitConnection()
        {
            //             SPList membershipList;
            SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    try
                    {
                        //
                        // Initialize SharePoint list connection.
                        //

                        _siteCollection = new SPSite(_pSiteUrl);
                        _mySite = _siteCollection.OpenWeb();
                        _pMembershipList = _mySite.Lists[_pMembershipListName];

                    }
                    catch (Exception ex)
                    {
                        throw new Exception("The system failed to correctly retrieve the membership list " + ex.Message);
                    }
                });
            return _pMembershipList;

        }

        private void DisposeConnection()
        {
            _mySite.Dispose();
            _siteCollection.Dispose();
        }

        #endregion

        #region Methods

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            SPList membershipList = InitConnection();

            DataTable usersAndRoles = membershipList.Items.GetDataTable();
            var reader = new DataTableReader(usersAndRoles);
            var userNames = new List<string>();
            while (reader.Read())
            {
                if (roleName == reader.GetString((int)reader.GetOrdinal("Role")))
                {
                    if (1 >= reader.GetString((int)reader.GetOrdinal("Email")).IndexOf(usernameToMatch, System.StringComparison.Ordinal))
                    {
                        userNames.Add(reader.GetString((int)reader.GetOrdinal("Email")));
                    }
                }
            }

            reader.Dispose();
            usersAndRoles.Dispose();
            DisposeConnection();

            return userNames.ToArray();
        }

        public override string[] GetAllRoles()
        {
            SPList membershipList = InitConnection();

            try
            {
                SPField roleField = membershipList.Fields[_pRoleFieldName];
                var roleChoices = roleField as SPFieldChoice;
               
                    var roleSet = (string[]) new ArrayList(roleChoices.Choices).ToArray(typeof (string));
                    DisposeConnection();
                    return roleSet;
                
            }
            catch (Exception e)
            {
                DisposeConnection();
                throw new Exception("The method or operation GetAllRoles threw this errhor: " + e.Message);
            }

          
        }

        public override string[] GetRolesForUser(string username)
        {
            var membershipList = InitConnection();

            var query = new Microsoft.SharePoint.SPQuery
                            {
                                Query =
                                    String.Format(
                                        "<Where><Eq><FieldRef ProductName='Email'/><Value Type='Text'>{0}</Value></Eq></Where>",
                                        username)
                            };
            SPListItemCollection listItems = membershipList.GetItems(query);

            string roleName = string.Empty;

            foreach (SPListItem userRow in listItems)
            {
                const string delimiter = "' ";
                const string roleField = "ows_Role='";

                // find ows_Role in the userID.XML
                int startIndex = userRow.Xml.IndexOf(roleField, System.StringComparison.Ordinal);
                if (0 < startIndex)
                {
                    int endIndex = userRow.Xml.IndexOf(delimiter, startIndex, System.StringComparison.Ordinal);
                    roleName = userRow.Xml.Substring((startIndex + roleField.Length),
                                                    (endIndex - (startIndex + roleField.Length)));
                }
            }

            // our particular implementation only allows a single role per user but we must return a string array
            string[] roleNames = { roleName };

            DisposeConnection();

            return roleNames;
        }

        public override string[] GetUsersInRole(string roleName)
        {
            SPList membershipList = InitConnection();

            DataTable usersAndRoles = membershipList.Items.GetDataTable();
            var reader = new DataTableReader(usersAndRoles);
            var userNames = new List<string>();
            while (reader.Read())
            {
                if (roleName == reader.GetString((int) reader.GetOrdinal("Role"))) 
                {
                    userNames.Add(reader.GetString((int) reader.GetOrdinal("Email"))); 
                }
            }

            reader.Dispose();
            usersAndRoles.Dispose();
            DisposeConnection();

            return userNames.ToArray();
        }

        #region Initialize
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException("config");

            if (name == null || name.Length == 0)
                name = "CLRole";

            // Initialize the abstract base class.  
            base.Initialize(name, config);

            _pSiteUrl = GetConfigValue(config["SiteURL"], "");
            _pMembershipListName = GetConfigValue(config["MembershipList"], "");
            _pRoleFieldName = GetConfigValue(config["RoleField"], "Role");            
        }
        #endregion


        public override bool IsUserInRole(string username, string roleName)
        {
            bool roleMatch = false;

            SPList membershipList = InitConnection();

            SPQuery query = new Microsoft.SharePoint.SPQuery();
            query.Query = String.Format("<Where><Eq><FieldRef ProductName='Email'/><Value Type='Text'>{0}</Value></Eq></Where>", username);
            SPListItemCollection listItems = membershipList.GetItems(query);

            string userRoleName = string.Empty;

            foreach (SPListItem userRow in listItems)
            {
                string delimiter = "' ";
                string roleField = "ows_Role='";

                // find ows_Role in the userID.XML
                int startIndex = userRow.Xml.IndexOf(roleField);
                if (0 < startIndex)
                {
                    int endIndex = userRow.Xml.IndexOf(delimiter, startIndex);
                    userRoleName = userRow.Xml.Substring((startIndex + roleField.Length),
                                                    (endIndex - (startIndex + roleField.Length)));

                    if (userRoleName == roleName)
                    {
                        roleMatch = true;
                    }
                }
            }

            DisposeConnection();

            return roleMatch;
        }

        public override bool RoleExists(string roleName)
        {
            SPList membershipList = InitConnection();

            try
            {
                SPField RoleField = membershipList.Fields[_pRoleFieldName];
                SPFieldChoice RoleChoices = RoleField as SPFieldChoice;
                foreach (string IndividualRole in RoleChoices.Choices)
                {
                    if (roleName.ToUpper() == IndividualRole.ToUpper())
                        return true;
                }
                DisposeConnection();
                return false;
            }
            catch (Exception e)
            {
                DisposeConnection();
                throw new Exception("The method or operation RoleExists threw this error: " + e.Message);
            }
        }
        #endregion

        #region Deliberately Not Implemented Methods

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            // AddUsersToRoles is deliberately not implemented in this provider as the functionality is expected to be handled in the SharePoint list
            // users created by the Membership provider are automatically given minimal permissions
        }

        public override void CreateRole(string roleName)
        {
            throw new Exception("The method or operation CreateRole is deliberately not implemented in this provider as the functionality is expected to be handled in the SharePoint list.");
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new Exception("The method or operation DeleteRole is deliberately not implemented in this provider as the functionality is expected to be handled in the SharePoint list.");
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new Exception("The method or operation RemoveUsersFromRoles is deliberately not implemented in this provider as the functionality is expected to be handled in the SharePoint list.");
        }


        #endregion
    } 
}
